﻿using MP3Sharp.Decoding;
using System;
using System.Collections.Generic;
using System.Text;

namespace MP3SharpFix
{
    public class Mp3Frame : MP3Sharp.Decoding.Header
    {
        //public bool h_copyright, h_original;
        //public int h_layer, h_protection_bit, h_bitrate_index, h_padding_bit, h_mode_extension;
        //public int h_mode;
        //public int h_number_of_subbands, h_intensity_stereo_bound;
        //public int h_sample_frequency;
        //public int h_version;

        //public int framesize;
        //public int nSlots;


        public uint framedataaddress;
        public byte[] framedata;// framedata 对齐到四字节，方便后续处理

        public int GetSampleCount()
        {
            if (h_layer == 1) return 384;
            else if (h_layer == 2) return 1152;
            else
            {
                if (h_version == Mp3Reader.MPEG1) return 1152;
                else
                    return 576;
            }
        }
        public int GetFrequency()
        {
            return Mp3Reader.frequencies[h_version][h_sample_frequency];
        }
        public void ReadData(System.IO.Stream stream)
        {
            //计算对齐到4字节，不够补齐

            int len = this.framesize / 4;
            if (this.framesize % 4 != 0)
                len++;

            if (h_protection_bit == 0 && crc == null)
                crc = new Crc16();
            this.framedata = new byte[len * 4];
            stream.Read(this.framedata, 0, this.framesize);


            if (h_protection_bit == 0)
            {
                // frame contains a crc checksum\
                byte[] buf = new byte[2];
                stream.Read(buf, 0, 2);
                checksum = (short)(buf[0] << 8 | buf[1]);

            }
            else
            {
            }
        }
        public int calculate_framesize()
        {
            if (h_layer == 1)
            {
                framesize = (12 * Mp3Reader.bitrates[h_version][0][h_bitrate_index]) / Mp3Reader.frequencies[h_version][h_sample_frequency];
                if (h_padding_bit != 0)
                    framesize++;
                framesize <<= 2; // one slot is 4 bytes long
                nSlots = 0;
            }
            else
            {
                framesize = (144 * Mp3Reader.bitrates[h_version][h_layer - 1][h_bitrate_index]) /
                            Mp3Reader.frequencies[h_version][h_sample_frequency];
                if (h_version == Mp3Reader.MPEG2_LSF || h_version == Mp3Reader.MPEG25_LSF)
                    framesize >>= 1;
                // SZD
                if (h_padding_bit != 0)
                    framesize++;
                // Layer III slots
                if (h_layer == 3)
                {
                    if (h_version == Mp3Reader.MPEG1)
                    {
                        nSlots = framesize - ((h_mode == Mp3Reader.SINGLE_CHANNEL) ? 17 : 32) - ((h_protection_bit != 0) ? 0 : 2) -
                                 4; // header size
                    }
                    else
                    {
                        // MPEG-2 LSF, SZD: MPEG-2.5 LSF
                        nSlots = framesize - ((h_mode == Mp3Reader.SINGLE_CHANNEL) ? 9 : 17) - ((h_protection_bit != 0) ? 0 : 2) -
                                 4; // header size
                    }
                }
                else
                {
                    nSlots = 0;
                }
            }
            framesize -= 4; // subtract header size

            return framesize;
        }

        public VBRInfo ParseVBR()
        {

            // Xing first
            int offset;
            if (this.h_version == Mp3Reader.MPEG1 && this.h_mode != Mp3Reader.SINGLE_CHANNEL)
            {
                offset = 32;
            }
            else if ((this.h_version == Mp3Reader.MPEG2_LSF || this.h_version == Mp3Reader.MPEG25_LSF) && this.h_mode == Mp3Reader.SINGLE_CHANNEL)
            {
                offset = 9;
            }
            else
            {
                offset = 17;
            }
            var buf = new byte[4];
            //Array.Copy(this.framedata, 32, buf, 0, 4);
            //var text1 = System.Text.Encoding.ASCII.GetString(buf);
            //Array.Copy(this.framedata, 9, buf, 0, 4);
            //var text2 = System.Text.Encoding.ASCII.GetString(buf);
            //Array.Copy(this.framedata, 17, buf, 0, 4);
            //var text3 = System.Text.Encoding.ASCII.GetString(buf);


            Array.Copy(this.framedata, offset, buf, 0, 4);
            if (buf[0] == 'X' && buf[1] == 'i' && buf[2] == 'n' && buf[3] == 'g'
             || buf[0] == 'I' && buf[1] == 'n' && buf[2] == 'f' && buf[3] == 'o')
            {
                offset += 4;

                VBRInfo info = new VBRInfo();
                info.Channels = this.h_mode == Mp3Reader.SINGLE_CHANNEL ? 1 : 2;
                info.SampleRate = this.GetFrequency();
                info.SampleCount = this.GetSampleCount();

                Array.Copy(this.framedata, offset, buf, 0, 4);
                offset += 4;
                var flags = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];

                // frame count
                if ((flags & 0x1) != 0)
                {
                    Array.Copy(this.framedata, offset, buf, 0, 4);
                    offset += 4;
                    info.VBRFrames = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
                }

                // byte count
                if ((flags & 0x2) != 0)
                {
                    Array.Copy(this.framedata, offset, buf, 0, 4);
                    offset += 4;
                    info.VBRBytes = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
                }

                // TOC
                if ((flags & 0x4) != 0)
                {
                    // we're not using the TOC, so just discard it
                    //if (Read(offset, buf) != 100) return null;
                    offset += 100;
                }

                // scale
                if ((flags & 0x8) != 0)
                {
                    Array.Copy(this.framedata, offset, buf, 0, 4);
                    offset += 4;
                    info.VBRQuality = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
                }
                return info;
            }

            // then VBRI (kinda rare)
            offset = 32;
            Array.Copy(this.framedata, offset, buf, 0, 4);
            if (buf[0] == 'V' && buf[1] == 'B' && buf[2] == 'R' && buf[3] == 'I')
            {
                VBRInfo info = new VBRInfo();
                info.Channels = this.h_mode == Mp3Reader.SINGLE_CHANNEL ? 1 : 2;
                info.SampleRate = this.GetFrequency();
                info.SampleCount = this.GetSampleCount();

                // VBRI is "fixed" size...  Yay. :)
                buf = new byte[26];
                Array.Copy(this.framedata, offset, buf, 0, 26);
                offset += 26;
                //if (Read(36, buf) != 26) return null;

                // Version
                var version = buf[4] << 8 | buf[5];

                // Delay
                info.VBRDelay = buf[6] << 8 | buf[7];

                // Quality
                info.VBRQuality = buf[8] << 8 | buf[9];

                // Bytes
                info.VBRBytes = buf[10] << 24 | buf[11] << 16 | buf[12] << 8 | buf[13];

                // Frames
                info.VBRFrames = buf[14] << 24 | buf[15] << 16 | buf[16] << 8 | buf[17];

                // TOC
                // entries
                var tocEntries = buf[18] << 8 | buf[19];
                var tocScale = buf[20] << 8 | buf[21];
                var tocEntrySize = buf[22] << 8 | buf[23];
                var tocFramesPerEntry = buf[24] << 8 | buf[25];
                var tocSize = tocEntries * tocEntrySize;

                //var toc = new byte[tocSize];
                if ((this.framesize - offset) < tocSize) return null;
                //if (Read(62, toc) != tocSize) return null;

                return info;
            }

            return null;
        }


    }
}
